﻿using System;
using System.IO;
using System.Xml;
using Main.Structure;
using Main.Substructure;

namespace Main.Database
{
    /// <summary>
    /// This class contains variables and methods used to load pre-existing client's into the Kernel.
    /// </summary>
    public static class Clients
    {
        // Local variables:
        private static XmlDocument xDoc = new XmlDocument(); // Used to read data from XML files.
        private static XmlWriter xWriter; // Used to write data to XML files.
        private static object syncObject = new object(); // Object used to prevent cross-threading.

        /// <summary>Counts how many client files there are, and loads them all.</summary>
        public static bool Load()
        {
            lock (syncObject)
            {
                // We wrap this all with a try/catch, because if data can't be read, then something went wrong.
                // If something went wrong, it'll return with false so we know. Otherwise, it returns true.
                try
                {
                    // String array of client file locations
                    var clientList = Directory.GetFiles(Hub.Configuration.CLIENT_PATH);

                    // For however many file locations in the list, we do the following...
                    // Note that "element" stands for one client's file in the entire list.
                    // For example, if there are 5 files in [program path]\Data\Clients, element will loop through
                    // each file and treat it as a client's file.
                    foreach (string element in clientList)
                    {
                        xDoc.Load(element); // Load the xDoc with the client's file.
                        var directorySplit = element.Split('\\'); // Separate directories so we are left with "[accountID].xml" at the last array position
                        var accountIDString = directorySplit[directorySplit.Length - 1].Split('.'); // Now we're left with "[accountID]" and "xml"
                        uint accountID = 0; // Assign 0 to this variable because no Acc ID should be 0 and will be used for error catching.

                        // Try to parse the client file name as their account ID. If it can't, the value will stay 0.
                        UInt32.TryParse(accountIDString[0], out accountID);

                        // If the account ID is still 0, there was an error. Throw an exception so we return false.
                        if (accountID == 0) { throw new Exception(); }

                        #region Client Information
                        // Create a new Client variable using the account ID and load their information by node.
                        Client client = new Client(accountID);
                        client.Street = xDoc.SelectSingleNode("Client/Address/Street").InnerText;
                        client.City = xDoc.SelectSingleNode("Client/Address/City").InnerText;
                        client.State = xDoc.SelectSingleNode("Client/Address/State").InnerText;
                        client.Zip = xDoc.SelectSingleNode("Client/Address/Zip").InnerText;
                        client.FirstName = xDoc.SelectSingleNode("Client/FirstName").InnerText;
                        client.LastName = xDoc.SelectSingleNode("Client/LastName").InnerText;
                        client.Phone = xDoc.SelectSingleNode("Client/Phone").InnerText;
                        client.Notes = xDoc.SelectSingleNode("Client/Notes").InnerText;
                        #endregion

                        // Try to add the client to the Kernel. Should be okay every time.
                        Kernel.Clients.TryAdd(accountID, client);
                    }

                    // Returns true if everything went okay.
                    return true;
                }
                catch (Exception) { return false; }
            }
        }

        /// <summary>This method creates a new client file based on information passed to it.</summary>
        /// <param name="client">The client information to create.</param>
        public static bool Create(Client client)
        {
            lock (syncObject)
            {
                try
                {
                    // A lot of code for writing a new XML file...
                    #region XmlWriter Code
                    xWriter = XmlWriter.Create(Hub.Configuration.CLIENT_PATH + client.AccountID + ".xml");
                    xWriter.WriteStartDocument();
                    xWriter.WriteStartElement("Client");
                    xWriter.WriteStartElement("FirstName");
                    xWriter.WriteString(client.FirstName);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("LastName");
                    xWriter.WriteString(client.LastName);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("Address");
                    xWriter.WriteStartElement("Street");
                    xWriter.WriteString(client.Street);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("City");
                    xWriter.WriteString(client.City);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("State");
                    xWriter.WriteString(client.State);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("Zip");
                    xWriter.WriteString(client.Zip);
                    xWriter.WriteEndElement();
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("Phone");
                    xWriter.WriteString(client.Phone);
                    xWriter.WriteEndElement();
                    xWriter.WriteStartElement("Notes");
                    xWriter.WriteString(client.Notes);
                    xWriter.WriteEndElement();
                    xWriter.WriteEndElement();
                    xWriter.WriteEndDocument();
                    #endregion
                    XmlDocument xDoc = new XmlDocument();
                    xDoc.Save(xWriter); // Saves the new client file.
                    xWriter.Flush();
                    xWriter.Close();
                    client.EditAll(); // Does a final save and formats the text to be more readable.
                    Kernel.Clients.TryAdd(client.AccountID, client); // Add this new client to the pool of clients
                    return true;
                }
                catch (Exception) { return false; }
            }
        }

        /// <summary>This method deletes a client file based on the account ID passed to it.</summary>
        /// <param name="accountID">The ID of the account that is being deleted.</param>
        public static bool Remove(Client client)
        {
            lock (syncObject)
            {
                try
                {
                    client.Wipe();
                    Kernel.Clients.TryRemove(client.AccountID, out client);
                    return true;
                }
                catch (Exception) { return false; }
            }
        }
    }
}
